home *** CD-ROM | disk | FTP | other *** search
/ Amoszine 9 / Amoszine 9 (Disk 3 of 3).adf / AC_Amos_Almanac.lha / Amosfiles.asc next >
Text File  |  1992-09-02  |  88KB  |  1,630 lines

  1. THE COMPLETE AMOS ALMANAC
  2.  
  3. A collection of Amiga Computing magazine's Amos Almanac columns, issues 42 to 58, Nov 1991 to March 1993.
  4.  
  5. ___________________________________________________
  6.  
  7.  
  8. THE COMPLETE AMOS ALMANAC
  9.  
  10.  
  11. Introduction
  12.  
  13. Welcome to the Amiga Computing Amos tutorial collection, a mammoth compendium of almost two years of Amos articles from the pages of the Almanac. Within this text file you should find the most complete step-by-step tutorial on Amos usage ever brought together in one place, including a complete guide to creating Pacman-style games and countless hints and programming tips.
  14.  
  15. As the series was originally printed one article at a time and backed up by monthly CoverDisks, you may find at times that the text assumes that, for instance, you have a few sprites or a background picture on which to practice. These files would have been supplied with the original article, but due to constraints of space they are not present on this disk. Simply substitute example files from the Amos program disks when this situation arises.
  16.  
  17. Please note that at any time you may obtain a printout of the text by holding down the Alt-Shift-O key combination. For details on selecting parts of the text to print and other functions of the text reader, hit the Help key.
  18.  
  19. ___________________________________________________
  20.  
  21.  
  22. Issue 42 ­ November 1991
  23. ? Putting together various previously discussed "modules" as the Pacman game begins to take shape
  24.  
  25. Entertainment software is big business now, and people have to be a little bit more creative to produce a good game, something which can be distinctly different to a good seller! Hopefully Amos will help you to spend a lot more of your time exercising these creative energies.
  26.  
  27. One important thing to remember about games software is that a lot of programmers cheat. We have covered different methods of ?cheating? in previous issues. Some of the most amazing effects seen in games are, in fact, merely illusion ­ screen swapping, colour cycling and palette switching are just some of the ways to get amazing results without compromising the speed of your program.
  28.  
  29. Almost anybody can use these methods, but the real skill is in integrating them with the software so that they are invisible to the player, while at the same time making him or her think ?wow, I wonder how they did that??.
  30.  
  31. OK, the first step in any piece of software is to set up your screen, we?ve done all of this before ­ if you missed it then buy the back issues ­ so I won?t take you through all of the old details again:
  32.  
  33.     ' Set up
  34.     Screen Open 0,320,200,16,Lowres
  35.     Curs Off
  36.     Flash Off
  37.     Cls 0
  38.     Get Sprite Palette
  39.     Double Buffer
  40.     Autoback 0
  41.  
  42. Now we have the task of initialising all of the variables that we will use. Although Amos ­ and most other versions of Basic for that matter ­ does not require you to do this, it is a habit you should get into. After all, you won?t be using Amos forever, will you?
  43.  
  44. We will need to keep track of the X and Y position of our character, so we will use two variables call X_GOOD and Y_GOOD. As well as storing the position of our character the joystick status will have to be stored, so we will call that variable WAY:
  45.  
  46.     X_GOOD=150
  47.     Y_GOOD=100
  48.     WAY=0
  49.  
  50. Of course we will also need to move the bad guy around, so we will call its X and Y co-ordinates X_BAD and Y_BAD:
  51.  
  52.     X_BAD=0
  53.     Y_BAD=0
  54.  
  55. Finally we may want to introduce individual speeds for each of the characters in the game, so we will call these ­ guess what?  ­ GOOD_SPEED and BAD_SPEED. Notice that by using meaningful variable names we can tell a glance what a particular section of code is doing, but be careful of falling into the trap of ending up with variable names 40 characters long ­ they can be a real drag to type in!
  56.  
  57.     GOOD_SPEED=1
  58.     BAD_SPEED=1
  59.  
  60. Ohhhh, I almost forgot. This game is very simple and because of this it is going to be blindingly fast, so in order to slow it down we will only update everything occasionally. It sounds strange I know, but all will become clear very soon.
  61.     The variable we are going to use to control this is called T ­ or time! ­ and the variable used to hold the score is called SCORE:
  62.  
  63.     T=1
  64.     SCORE=0
  65.  
  66. Now we have to stick the player and the bad guy on to the screen. For this example program we are using BOBs, but you could use hardware SPRITEs:
  67.  
  68.     Bob 1,X_GOOD,Y GOOD,1
  69.     Bob 2,X_BAD, Y_BAD,2
  70.  
  71. Now for the main part of the game: 
  72.  
  73.     Repeat
  74.  
  75. The first line here tells the program that we only want to execute everything inside the IF structure when the variable T has a value of two. At the moment it only has a value of one:
  76.  
  77.     If T=2
  78.  
  79. Our next task is to check the joystick to see if a movement has been made. We will use the JOY() function rather than the JUP/JDOWN functions, because it is more versatile. A fuller explanation as to why this is will be given in the next issue.
  80.     We store the current joystick value ­ which is a number between 0 and 16 ­ in the variable WAY. If WAY has a value greater than zero then we know that the joystick is being moved, and we can then test the direction and move our character:
  81.  
  82.     WAY=Joy(1)
  83.     If WAY>0
  84.  
  85. At this point we know that our man has moved so we can increase the score by one:
  86.  
  87.     Inc SCORE
  88.  
  89. Now comes the joystick testing bit. In a previous issue we saw how the JOY() function returns values depending on how it is currently positioned. Just to recap, these are the values for the four basic directions: UP=1, DOWN=2, LEFT=4, RIGHT=8.
  90.     Knowing this we can see if the player wants to move the character and so can increase/decrease the X_GOOD/Y_GOOD variables accordingly:
  91.  
  92.     If WAY=8
  93.         Add X_GOOD,GOOD_SPEED,0 To 319
  94.     End If
  95.     If WAY=4
  96.         Add X_GOOD,-GOOD_SPEED,0 To 319
  97.     End If
  98.     If WAY=1
  99.         Add Y_GOOD,-GOOD_SPEED,0 To 199
  100.     End If
  101.     If WAY=2
  102.         Add Y_GOOD,GOOD_SPEED,0 To 199
  103.     End If
  104.  
  105. Another trick when writing a game is not to update anything on the screen unless it has moved. For this reason we will only redraw our little character when the joystick has been moved:
  106.  
  107.     Bob 1,X_GOOD,Y_GOOD,1
  108.     End If
  109.  
  110. Here is a tricky question, with a very simple answer. How do you make a nasty home-in on your good guy? Well, imagine you were playing a game where you had to run after somebody. The brain would follow a simple set of rules, like: ?If the person is to the left of me, I must move left,? and, ?if the person is in front of me I must move forward.?
  111.     These are the simple rules we can follow to make a ?homer?. Of course most games have a slightly longer list of rules to control movement of bad guys and good guys, but at the end of the day they are still only a list of rules that the program must follow.
  112.     I am sure you have played many games where after a while you realise that if you perform a certain action at a certain point, you can make the program do the same thing almost every time. This is because it is just following a set of simple ­ or complicated ­ rules:
  113.     
  114.     If X_GOOD<X_BAD
  115.         Add X_BAD,-BAD_SPEED
  116.     Else
  117.         Add X_BAD,BAD_SPEED
  118.     End If
  119.     If Y_GOOD<Y_BAD
  120.         Add Y_BAD,-BAD_SPEED
  121.     Else
  122.         Add Y_BAD,BAD_SPEED
  123.     End If
  124.     
  125. At this point we update the position of the bad guy and increase the value of the variable T. Remember that the ADD statement below has been written so that the number will wrap around from 1 to 2:
  126.     
  127.     Bob 2,X_BAD,Y_BAD,2
  128.     Add T,1,1 To 2
  129.     
  130. As we have seen earlier, to slow the game down we only update characters every second time we go through the loop. If the value of T is not 2 the program will just execute the next couple of lines and go back to the beginning:
  131.     
  132.     Else
  133.         Add T,1,1 To 2
  134.     End If
  135.     
  136. Finally, we must set a stop condition on the REPEAT/UNTIL loop. In this case the program will stop if Bob number one collides with any other Bob. If a collision is detected your score is printed and the game ends!
  137.     
  138.     Until Bob Col(1)
  139.     Boom
  140.     Print ?YOU ARE DEAD!!!! YOUR SCORE IS?;SCORE
  141.     Update
  142.     End
  143.     
  144. How long can you run around avoiding the nasty invader type beastie?. Why not experiment a little bit and see if you can add more bad guys and perhaps objects to collect. Before long you could be writing the follow up to Llamatron!
  145.  
  146. Finally, do not try to compile the game unless you slow it down, because it will end up impossibly fast! Remember that no piece of software is fixed, and if you do not like something about a game you write then change it!
  147.  
  148.  
  149. Issue 43 ­ December 1991
  150. ? Adding a maze to the rapidly developing Pacman game
  151.  
  152. Last month we saw how to get the good guy under joystick control and how to make the bad guy follow him. This month we will take a look at how to put a maze up on the screen.
  153.  
  154. OK, if you look at the screenshot on this page you should spot a nice picture of some maze blocks. In fact there are eight in total, four corners, two straight pieces, a small blob thing and a collectable pill (was Pacman a junkie?).
  155.  
  156. Why use blocks to build up a maze? The answer is simple ­ flexibility. By using blocks we can generate lots of different mazes using up only a fraction of the memory that a picture would take up.
  157.  
  158. If you take another look at the picture of the blocks you will notice they have numbers underneath. These will be used to build up our mazes. For example to build up a simple border we would use the following data:
  159.     
  160.     DATA "12222222222222222223"
  161.     DATA "4                  4"
  162.     DATA "4                  4"
  163.     DATA "4                  4"
  164.     DATA "4                  4"
  165.     DATA "4                  4"
  166.     DATA "4                  4"
  167.     DATA "4                  4"
  168.     DATA "4                  4"
  169.     DATA "4                  4"
  170.     DATA "4                  4"
  171.     DATA "52222222222222222226"
  172.  
  173. The number one represents the top left-hand corner and the number six represents the bottom-right.
  174.     To display this on-screen requires a little more work. The first thing to do is to dimension an array to hold the maze data. As each block is 16 x 16 pixels our maze can only be made up of 20 blocks across and 12 blocks down. Because we are going to hold the block numbers in a string array we only need to dimension it to 11 elements:
  175.  
  176.     Dim MAZE$(11)
  177.  
  178. The next step is to open up to a lo-res screen and clear it ready for drawing:
  179.  
  180.     Screen Open 0,320,200, 16, Lowres
  181.     Flash Off
  182.     Curs Off
  183.     Cls 0
  184.     Get Icon Palette
  185.  
  186. I have already prepared an icon bank for you on the CoverDisk which must be loaded into this listing before it will work:
  187.  
  188.     Load "MAZE_ICONS.ABK"
  189.  
  190. Things start to get a little more complex now. First we must read in a line of our maze data:
  191.  
  192.     For LOP=0 To 11
  193.     Read MAZE$(LOP)
  194.  
  195. Next we have to look at each part of that string to find out what maze block we would like to position on the screen at the next point:
  196.  
  197.     For LOP2=0 To 19
  198.     BLOCK-Val(Mid$(MAZE$(LOP), LOP2+1,1))
  199.  
  200. I always like to be careful when writing something like this. It is very easy to mistype a character so it is always worth putting a check in for strange values. Using this method we can automatically generate spaces in the maze if we want them while avoiding any error messages which Amos would throw up if we tried to display an icon that did not exist:
  201.  
  202.     If BLOCK>0 and BLOCK<9
  203.     Paste Icon LOP2*16,LOP*16,BLOCK
  204.     End If
  205.     Next LOP2
  206.     Next LOP
  207.  
  208. The maze!
  209.  
  210.     Data "12222222222222222223"
  211.     Data "48888888888888888884"
  212.     Data "48123812381223812384"
  213.     Data "484 485268522684 484"
  214.     Data "484 488888888888 484"
  215.     Data "48526812222223852684"
  216.     Data "4888884      4888884"
  217.     Data "48123852222226812384"
  218.     Data "484 488888888884 484"
  219.     Data "48526812222223852684"
  220.     Data "4888884      4888884"
  221.     Data "5222226      5222226"
  222.  
  223. Erm? What next? Well, it's a bit of a surprise actually. The method I have just showed you to draw the maze screens is OK, but we need a quick way to look at the maze shape to find out where the blocks are.
  224.  
  225. This way we can control the movement of any creatures we decide to put into the maze without resorting to slow and complex collision detection commands.
  226.  
  227. So we will now put all of the data needed to create a maze into an Amos memory bank which will be 240 bytes long (20 blocks wide x 12 blocks tall):
  228.  
  229.     Reserve As Work 10,240
  230.  
  231. We now have to set up that funky screen and load those icons again:
  232.  
  233.     Screen Open 0,320,200,16,Lowres
  234.     Flash Off
  235.     Curs Off
  236.     Cls 0
  237.     Get Icon Palette
  238.     Load "MAZE_ICONS.ABK"
  239.  
  240. This time we will read the data into memory bank 10 which we reserved earlier:
  241.  
  242.     For LOP=0 To 11
  243.     Read MAZE$
  244.     For LOP2=0 To 20
  245.  
  246.     BLOCK=Val(Mid$(MAZE$, LOP2+1,1))
  247.  
  248. Take note of the formula that is used to calculate the position of each block ­ we will use a slightly adapted version of this for collision detection:
  249.  
  250.     POSITION=Start(10)+(LOP*20)+LOP2
  251.     Poke POSITION,BLOCK
  252.     Next LOP2
  253.     Next LOP
  254.  
  255. Once that is stored we can draw the screen by reading the data.
  256.  
  257. Simple formula time! Next month when we start to more our pacman around the maze, and will need a routine to make sure it does not career into any walls. We can find this out by constantly keeping a track of the position of our pacman and then using the following formulae to see if any walls blocks its path:
  258.  
  259.     UP=((Y-1)*20)=X
  260.     DOWN=((Y+1*20)+X
  261.     LEFT=(Y*20)+(X-1)
  262.     RIGHT=(Y*20)=(X+1)
  263.  
  264. If that seems a little bit confusing don't worry, everything will become clear as mud (sorry crystal)...
  265.  
  266.  
  267. Issue 44 ­ January 1992
  268. ? Making our pacmen move around the maze
  269.  
  270. In the days before hardware sprites and automatic collision detection, programmers still managed to produce games by looking at position of players, enemies and background objects.  They could then calculate whether or not they overlapped.
  271.  
  272. The first thing we must do to do this is set a working screen and load the Pacman sprites and maze icons in memory:
  273.  
  274.     Reserve As Work 10,240
  275.     Screen Open 0,320,200,16,Lowres
  276.     Flash Off
  277.     Curs Off
  278.     Cls 0
  279.     Hide On
  280.     Load ?MAZE ICONS.ABK?
  281.     Load ?PACMAN_SPRITES.ABK?
  282.     Get Icon Palette
  283.     
  284. OK, now we must define some simple variables.  Those of you who have just started to learn how to program will notice the GLOBEL statement. This lets our program know that the variables X and Y are used in all parts of the program (including procedures).
  285.  
  286. If we did not execute this command, the procedures - which are really mini programs, independent of the main one ­ would assume that the variables X and Y were used only in themselves. It is probably easier to think of the GLOBEL as making the procedures share information:
  287.  
  288.     Globel X,Y
  289.     X=1
  290.     Y=1
  291.     MAKE_MAZE
  292.  
  293. OK, now is the interesting part. The formulas which are calculated into the variables UP, DOWN, LEFT and RIGHT check the position of our Pacman compared the maze data we have stored in
  294. bank 10. 
  295.  
  296. If the joystick is pushed in a direction and there is a pill found there, the  program will move the Pacman and erase the dot accordingly! If you remember how we built up the maze last time you will recall that the pills had a value of eight:
  297.  
  298.     Repeat
  299.         UP=((Y-1)*20+X
  300.         DOWN=((Y+1)*20+X
  301.         LEFT=(Y*20)+(X-1)
  302.         RIGHT=(Y*20)+(X+1)
  303.         Bob 1,16*X,16*Y,2
  304.         Wait 2
  305.         WAY=Joy(1)
  306.         If WAY<>0
  307.             If WAY=1 and Peek(Start(10)+UP)=8
  308.                 EACH_DOT
  309.                 Dec Y
  310.             End If
  311.             If WAY=2 and Peek(Start(10)+DOWN)=8
  312.                 EAT_DOT
  313.                 Inc Y
  314.             End If
  315.             If WAY=4 and Peek(Start(10)+LEFT)=8
  316.                 EAT_DOT
  317.                 Dec X
  318.             End If
  319.             If WAY=8 and Peek(Start(10)+RIGHT)=8
  320.                 EAT_DOT
  321.                 Inc X
  322.             End If
  323.              End If
  324.    Until False
  325.    End
  326.  
  327. This procedure erases the pill when the Pacman moves:
  328.  
  329.     Procedure EAT_DOT
  330.         Cls O,X*16+6,Y*16+6 To X*16+12,Y*16+12
  331.     End Proc
  332.  
  333. The following procedure is identical to the one we wrote last month to draw the maze:
  334.  
  335.     Procedure MAKE_MAZE
  336.         For LOP=0 To 11
  337.             Read MAZES
  338.             '
  339.             For LOP2=0 To 20
  340.                 BLOCK=Val(Mid$(MAZES,LOP2+1,1))
  341.                 POSITION=Start(10)+(LOP*20)+LOP2
  342.                 '
  343.                 Poke POSITION,BLOCK
  344.                 '
  345.             Next LOP2
  346.             '
  347.             For LOP=0 To 11
  348.                 For LOP2=0 To 19
  349.                     BLOCK=Peek(Start(10)+(LOP*20)+LOP2)
  350.                     If BLOCK<>0
  351.                     Paste Icon LOP2*16,LOP*16,BLOCK
  352.                 End If
  353.             Next LOP2
  354.         Next LOP
  355.         Wait Vbl
  356.         Double Buffer
  357.         '
  358.         Data ?12222222222222222223?
  359.         Data ?48888888888888888884?
  360.         Data ?48123812381223812384?
  361.         Data ?484 485268522684 484?
  362.         Data ?484 488888888884 484?
  363.         Data ?48526812222223852684?
  364.         Data ?4888884      4888884?
  365.         Data ?48123852222226812384?
  366.         Data ?484 488888888884 484?
  367.         Data ?48526812222223852684?
  368.         Data ?4888884      4888884?
  369.         Data ?5222226      5222226?
  370.     End Proc
  371.  
  372.  
  373. Issue 45 ­ February 1992
  374. ? Introducing ghosts to chase your pacman
  375.  
  376. As you will recall, we have now generated our maze and made a Pacman travel around it with our joysticks ­ now it?s time to introduce a nice ghostie to chase you. Some of the code we will be looking at will be familiar to you, but there are subtle differences between the program we looked at in the last issue and this one.
  377.  
  378. First we open our screens and reserve our bank to store the maze data. Then we load in the sprites and icons:
  379.  
  380.     Reserve As Work 10,240
  381.     Screen Open 0,320,200,16,Lowres
  382.     Flash Off
  383.     Curs off
  384.     Cls 0
  385.     Hide On
  386.     ?
  387.     Load ?PACMAN_SPRITES.ABK?
  388.     Load ?MAZE_ICONS.ABK?
  389.     Load ?MAZE_ICONS.ABK?
  390.     Get Icon Palette
  391.  
  392. Note that most of the code is now in separate procedures. This is to keep matters a little clearer when explaining things. As you write your own programs you will find it much more efficient to break them down into smaller, more manageable parts. This means that all of our variables must be declared as Global ­ if we do not do this, our procedures will not recognise them!
  393.  
  394. The next step is to generate the maze and execute the main loop:
  395.  
  396.     MAKE_MAZE
  397.     Repeat
  398.     Wait 2
  399.  
  400. Right, because we have changed things a little, the program now checks the joystick and moves our pacman by calling two procedures:
  401.  
  402.     CHECK_STICK
  403.     DO_PACMAN
  404.  
  405. Because our ghost is moving quite quickly we need to weigh the odds in our favour a little. To do this we will use a variable counter called PASS. Every time the loop is executed we increment this variable, and when it reaches three we move the ghost. So for every three moves we could make, the ghost will make one:
  406.  
  407.     If PASS=3
  408.     DO_GHOST
  409.     End If
  410.     Add
  411.     PASS,1,1 To 3
  412.  
  413. Finally, we will check to see if the ghost has hit the Pacman by comparing their co-ordinates. BX & BY are the ghost?s position X & Y are the Pacman?s position in the maze:
  414.  
  415.     Until(BX=X and BY=Y)
  416.     End
  417.  
  418. The next procedure is the one which makes the ghost so hard to beat. Remember how a couple of issues ago we looked at baddie intelligence? This program uses exactly the same method and follows these rules:
  419.  
  420. 1] IF PACMAN IS LEFT OF GHOST THEN MOVE GHOST LEFT ELSE MOVE GHOST RIGHT
  421.  
  422. 2] IF PACMAN IS ABOVE GHOST THEN MOVE GHOST UP ELSE MOVE GHOST DOWN
  423.  
  424. Of course, if a wall is in the way the pacman cannot move. You can easily overcome this by introducing more complex rules. Remember ­ baddie intelligence is always governed by a set of rules, simple or complex:
  425.  
  426.     Procedure DO_GHOST
  427.     If BX<>X
  428.      GHOST_RIGHT
  429.     Else
  430.      If BX>X
  431.       GHOST_LEFT
  432.      End If
  433.     End If
  434.     If BY>Y
  435.      GHOST_UP
  436.     Else
  437.      If BY<>Y
  438.       GHOST_DOWN
  439.      End If
  440.     End If
  441.     Bob 2,16*BX,16*BY,4
  442.     End Proc
  443.  
  444. The following procedures check to see if a wall is in the way before moving the ghost. Any value found in the maze band other than eight is classified as a wall. In more complex versions of the game you could check for power pellets, bonus fruits, and so on:
  445.  
  446.     Procedure GHOST_LEFT
  447.     B LEFT=(BY*20)+(BX-1)
  448.     If Peek(Start(10)+B_LEFT)=8
  449.      Dec BX
  450.     End If
  451.     End Proc
  452.     Procedure GHOST_RIGHT
  453.     B_RIGHT=(BY*20)+(BX+1)
  454.     If PEEK(Start(10)+B_RIGHT)=8
  455.      Inc BX
  456.     End If
  457.     End Proc
  458.     Procedure GHOST_UP
  459.     B_UP=((BY-1)*20)+BX
  460.     If Peek(Start(10)+B_UP)=8
  461.      Dec BY
  462.     End If
  463.     End Proc
  464.     Procedure GHOST_DOWN
  465.     B_DOWN=((BY+1)*20)+BX
  466.     If Peek(Start(10)+B_DOWN)=8
  467.      Inc BY
  468.     End If
  469.     End Proc
  470.  
  471. CHECK_STICK looks at the value stored in JOY(1). This contains a bitmap of the joystick position. If the value found is one it means that you are pushing the joystick up, two means down, four is left and eight is right. Just for reference, if the value of 16 is found then you have pressed Fire on the joystick!
  472.  
  473.     Procedure CHECK_STICK
  474.     WAY=Joy(1)
  475.     If WAY<>>0
  476.      If WAY=1 and Peek(Start(10)+UP)=8
  477.       EAT_DOT
  478.       Dec Y
  479.      End If
  480.      If WAY=2 and Peek(Start(10)+DOWN)=8
  481.       EAT_DOT
  482.       Inc Y
  483.      End If
  484.      If WAY=4 and Peek(Start(10)+LEFT)=8
  485.       EAT-DOT
  486.       DEC X
  487.      END IF
  488.      IF WAY=8 AND Peek(Start(10)+RIGHT)=8
  489.       EAT_DOT
  490.       Inc X
  491.      End If
  492.     End If
  493.     End Proc
  494.  
  495. This procedure does exactly the same as the routine we looked at last month. Basically it looks at the four directions surrounding the pacman to discover if a wall is in the way. It stores this information in the global variables UP, DOWN, LEFT, RIGHT:
  496.  
  497.     Procedure DO_PACMAN
  498.     UP=((Y-1)*20)=X    
  499.     DOWN=((Y=1)*20)+X
  500.     LEFT=(Y*20)+(X-1)
  501.     RIGHT=(Y*20)+(X+1)
  502.     Bob 1,16*X,16*Y,2
  503.     End Proc
  504.  
  505. The next procedure does, guess what? Yes it erases the dot!
  506.  
  507.     Procedure EAT_DOT
  508.     Cls 0,X*16+6,Y*16+6 To X*16+12,Y*16+12
  509.     End Proc
  510.  
  511. Finally comes the procedure to generate the maze, which we looked at in depth a couple of issues ago.
  512.  
  513.     Procedure MAKE_MAZE
  514.     For LOP=0 To 11
  515.      Read MAZE$
  516.      ?
  517.      For LOP2=0 To 20
  518.       BLOCK=Val(Mid$(MAZE$,LOP2+1,1))
  519.       POSITION=Start(10)+(LOP*20)+LOP2
  520.       ?
  521.       Poke POSITION,BLOCK
  522.       ?
  523.      Next LOP2
  524.     Next LOP
  525.     ?
  526.     For LOP=0 To 11
  527.      For LOP2=0 To 19
  528.       BLOCK=PEEK(Start(10)+(LOP*20)+LOP2)
  529.       If BLOCK<>>0
  530.        Paste Icon LOP2*16,BLOCK
  531.       End If
  532.      Next LOP2
  533.     Next LOP
  534.     Wait Vbl
  535.     Double Buffer
  536.     ?
  537.     Data "12222222222222222223"
  538.     Data ...
  539.  
  540.  
  541. Issue 46 ­ March 1992
  542. ? Taking a break from Pacman, and looking at Easy Amos, as well as some Funschool tips
  543.  
  544. Easy Amos is basically a version of Amos which has been designed for people who don?t know much about computer programming but want to learn, as well as people who know a little but find Amos just a little too daunting.
  545.  
  546. To describe it as a cut down version of Amos is a little unfair ­ there are a few commands and facilities which are missing (like menus) but it makes up for them with some really great new ones (like commands to load and play Soundtracker music without conversion!).
  547.  
  548. Easy Amos really is looking splendid. The manual ­ written by computer veteran Mel Croucher ­ is humorous and informative and incorporates lots of cartoons. There are loads of example programs on the accompanying disk which are documented and discussed in the manual, so there is only a little typing for those keyboard-shy beginners!
  549.  
  550. The whole appearance of the user interface has changed since its parent (Amos) was written. Everything is made up from the grey relief type boxes which we are so used to seeing in Workbench 2, and the editor now uses an eight colour screen to improve the rather bland look associated with four colour examples.
  551.  
  552. Everything about Easy Amos oozes friendliness. You can customise the actual language and the accompanying demos with your own name! It really is aimed at the absolute beginner.
  553.  
  554. One of the more advanced features of this new Amos is the Tutor. It is, in fact, a full source code debugger which will allow you to single step through your program in order to test it. You can set up break points and even set your own screens, Bobs, text and graphics up in a shrunk down window. 
  555.  
  556. This is really amazing and has to be seen to be believed. I understand that Europress Software will be taking this feature and adding it to an improved ?full? version of Amos currently dubbed ?Amos II?. Roll on that day!!!
  557.  
  558. HERE?S a fabo tip for all of you programming Fun School 4 owners. On the Under 5s and 5 to 7s package a new experimental sound extension has been used! This is compatible with the StarTrekker program (a SoundTracker clone) and will allow you not only to play Soundtracker modules without using that dodgy converter but also supports the synthetic instrument/Sound FX option in StarTrekker!
  559.  
  560. The file is called ?MUSIC.LIB? and is a direct replacement for the ?MUSIC.LIB? file contained inside your ?Amos_SYSTEM? directory, so all you have to do is copy it across. Unfortunately I do not have any details of the playing commands so you will have to route around the FS4 programs for more information about that.
  561.  
  562.  
  563. Issue 47 ­ April 1992
  564. ? An introduction to AMAL, the powerful Amos sub-language
  565.  
  566. Now it's time to really break free and attempt a task using something really meaty (or soya-beanie) if you are vegetarian) ­ AMAL.
  567.  
  568. We have covered AMAL previously, but not to write a whole game. Over the next couple of issues I will be showing you how to get the most out of this sub-language and more importantly how to use it in conjunction with the other (less powerful) parts of Amos.
  569.  
  570. You will notice that I have referred to AMAL as a sub-language. This is because it is a separate part of Amos and is quite capable of existing by itself. In many respects AMAL is similar to assembly language, especially in its use on mnemonics to represent the commands we use to create an AMAL program, and like assembly language, it must be well structured in order to keep tracks of any tasks we may ask of it.
  571.  
  572. To control AMAL we use a series of Channels ­ 16 in all. These can be assigned to control a single AMAL mini-program which will run alongside your main Amos program. Let's look at a way of using of AMAL. First we set up an AMAL channel using a command like this:
  573.     
  574.     Channel 1 To Screen Display 0
  575.  
  576. This would prepare your channel to accept an AMAL program. Now we will tell AMAL to feed the mouse co-ordinates into the external registers RA and RB, after which we will read and display them onscreen.
  577.  
  578. One thing to remember about AMAL is that you must type it exactly otherwise errors can occur quite easily. This is due to the fact that AMAL is case sensitive ­ that is, it can tell the difference between upper and lower case letters:
  579.     
  580.     mal 1,"Start: Let RA=XM ; Let RB=YM ; Jump Start ; "
  581.      Amal On1
  582.      Repeat
  583.         Print At(0,0);Amreg(0);" "
  584.        Print At(0,1);Amreg(1);" "
  585.      Until False
  586.  
  587. AMAL registers are like ordinary variables in Amos itself, and can be used to store numbers for calculations or later use. These are two types of AMAL register, internal and external. The internal registers are labelled R0 to R9 and are mainly used for temporary storage of values within an AMAL program. The external registers are labelled RA to RZ and are (or at least should be) used for communicating with the outside world.
  588.  
  589. Reading these registers from your main Amos program is simple ­ we just use the AMREG() command (see your Amos manual for a fuller explanation of AMREG). Incidentally, you can store values in the AMAL registers from your main Amos program once again using the AMREG() command..
  590.  
  591. Being a fully featured sub-language means that AMAL programs can be quite long. For this reason AMAL allows you to structure commands within strings. I know it sounds a little weird but you do get used to it ­ trust me!
  592.  
  593. In the previous example we saw how to create a simple loop jumping from the end of the string back to the label "Start". Labels used for structuring AMAL programs are all single letters of the alphabet, in upper case. Because AMAL ignores all lower case letters you can pad out the label to create something a little more meaningful.
  594.  
  595. The next example is made up of may smaller strings "glued" together t create a single long string. You don't really want to know this but joining two or more strings together is known as concatenation:
  596.     
  597.      Channel 0 To Screen Display 0
  598.     A$="   Start:"
  599.     A$=A$+"      Pause ; "
  600.     A$=A$+"      Let Y=YM-100 ; "
  601.     A$=A$+"      If XM-160<64 Jump Start ; "
  602.     A$=A$+"      Let X=XM-160 ; "
  603.     A$=A$+"Jump Start ; "
  604.     Amal0,A$
  605.     Amal On 0
  606.  
  607. This program will work in direct more and will allow you to move the default screen around with the mouse. It's a little like the larger program which appeared last month.
  608.  
  609. Notice the way I have put each command on a separate line. I have also padded out the short labels and commands with lower case letters so that should I come back to the program in a couple of months I will be able to work out what it does quite easily.
  610.  
  611. AMAL also allows you to execute a simple form of FOR?NEXT loop, the main difference between the AMAL version and the actual Amos version of the loop is that you cannot perform STEPs (if you are unsure what a STEP is, check your Amos manual). The following example does the same job as the previous program, but only for a limited amount of times:
  612.     
  613.      Channel 0 To Screen Display 0
  614.     A$="   For R0=1 To 80"
  615.     A$=A$+"Start: "
  616.     A$=A$+"      Pause ; "
  617.     A$=A$+"      Let Y=YM-100 ; "
  618.     A$=A$+"      If XM-160<64 Jump Start ; "
  619.     A$=A$+"      Let X=XM-160 ; "
  620.     A$=A$+"Next R0 ; "
  621.     Amal0,A$
  622.     Amal On 0
  623.  
  624. If you look at the Amosteroids game which came with Amos you will see that most of the work is dome by AMAL ­ it controls the starship and asteroids. In fact the only things Amos has to do is play the samples and update the score during the game.
  625.  
  626. These AMAL programs need not be limited to controlling aliens in Xenon MXXIIX ­ how about using them to make Bobs to follow your mouse? Or making constant calculations and feeding them into your main program using the AMAL registers?
  627.  
  628.  
  629. Issue 48 ­ May 1992
  630. ? Rewriting the Pacman game to take advantage of AMAL
  631.  
  632. If you can cast your mind back a couple of months, we were playing around with simple Bob movements using Amos. Our goal was to create a small Pacman game, which we did. Now we will look at a different method of creating such a game, using the Amos sub-language AMAL.
  633.  
  634. We took a look at the major AMAL functions in the last issue so I won?t be going into too much fine detail concerning the basic functions. Instead we will concentrate on the structure of an AMAL program.
  635.  
  636. The first thing to do is load in the Bobs for the game and set up our default screen stuff. If you are unsure how to get these Bobs loaded in ­ trust me when I say it?s not quite as straightforward as it sounds..
  637.  
  638.     Load ?GAME_SPRITES.ABK?
  639.     Screen Open 0,320,200,16,Lowres
  640.     Curs Off
  641.     Flash Off
  642.     Cls 0
  643.     Get Sprite Palette
  644.     Double Buffer
  645.     Autoback 0
  646.  
  647. Now comes the time to define our AMAL string. As you can see, I have built the program up into the string A$. AMAL ignores spaces so I have taken advantage of this to produce a clear piece of code which is easy to look at and ­ hopefully ­ to understand.
  648.  
  649. The first line sets up a label ?Start:? and after a brief pause stores the current joystick value in the register R0:
  650.  
  651.     A$=" Start: Pause ; Let R0=J1 ; "
  652.  
  653. By using comparisons we can then jump to routines depending on the current joystick action. As I have said before, the numbers returned by the joystick are 1=up, 2=down, 4=left, 5=right and in turn 9=up plus right (8+1=9), 6=down plus left (2+4=6) and so on.
  654.  
  655.     A$=A$="   If R0&8 Jump Right ; "
  656.     A$=A$="   If R0&4 Jump Left  ; "
  657.     A$=A$="   If R0&1 Jump Up  ; "
  658.     A$=A$="   If R0&2 Jump Down  ; "
  659.     A$=A$="   Jump Start     ;
  660.  
  661. The next four routines perform the actual movements of the Bob ­ for more details of how the Move command works see your Amos manual.
  662.  
  663.     A$=A$+"Right:           ; "
  664.     A$=A$+"    Move 10,0,2     ; "
  665.     A$=A$+"    Jump Start     ; "
  666.     A$=A$+"Left:           ; "
  667.     A$=A$+"    Move -10,0,2    ; "
  668.     A$=A$+"    Jump Start     ; "
  669.     A$=A$+"Up:            ; "
  670.     A$=A$+"    Move 0,-10,2    ; "
  671.     A$=A$+"    Jump Start     ; "
  672.     A$=A$+"Down:           ; "
  673.     A$=A$+"    Move 0,10,2     ; "
  674.     A$=A$+"    Jump Start     ; "
  675.     ?
  676.     For LOP=1 To 15
  677.       Bob LOP,Rnd(150),Rnd(100),1
  678.       Channel LOP To Bob LOP
  679.       Amal LOP,A$
  680.     Next LOP
  681.     ?
  682.     Wait Vbl
  683.  
  684. Amal On
  685.     ?
  686.     Direct
  687.  
  688. OK, so you don?t want to structure your AMAL programs, you could shorten them by just using the UPPERCASE characters. Just look at the following AMAL string. If you value your sanity, don?t try to type it in!
  689.  
  690.     A$="S:P;LR0=J1;"
  691.     A$=A$+"IR0&8JR;"
  692.     A$=A$+"IR0&4JL;"
  693.     A$=A$+"IR0&1JU;"
  694.     A$=A$+"IR0&2JD; "
  695.     A$=A$+"JS;"
  696.     A$=A$+"R:;"
  697.     A$=A$+"M10,0,2;"
  698.     A$=A$+"JS;"
  699.     A$=A$+"L:;"
  700.     A$=A$+"M-10,0,2;"
  701.     A$=A$+"JS;"
  702.     A$=A$+"U:;"
  703.     A$=A$+"M0,-10,2;"
  704.     A$=A$+"JS;"
  705.     A$=A$+"D:;"
  706.     A$=A$+"M0,10,2;"
  707.     A$=A$+"JS;"
  708.  
  709. Having fun? I hope so! The final part of this exciting instalment gives us an AMAL-controlled player and baddie:
  710.  
  711.     Load "GAME_SPRITES.ABK"
  712.     Screen Open 0,320,200,16,Lowres
  713.     Curs Off
  714.     Flash Off
  715.     Cls 0
  716.     Get Sprite Palette
  717.     Double Buffer
  718.     Autoback 0
  719.     Bob 1,150,100,1
  720.     Bob 2,20,20,2
  721.  
  722. The string A$ is exactly the same as in the first program except that the horizontal and vertical positions of the player are fed into the external registers RA and RB. These are then read inside the baddie control program stored in B$ to make that the evil beastie tracks us down!
  723.  
  724.     A$="  Start: Pause ; Let R0=J1  ; "
  725.     A$=A$+"    Let RA=X ; Let RB=Y ; "
  726.     A$=A$+"    If R0&8 Jump Right ; "
  727.     A$=A$+"    If R0&4 Jump Left  ; "
  728.     A$=A$+"    If R0&1 Jump Up   ; "
  729.     A$=A$+"    If R0&2 Jump Down  : "
  730.     A$=A$+"    Jump Start     ; "
  731.     A$=A$+"Right:           ; "
  732.     A$=A$+"    Move 10,0,2     ; "
  733.     A$=A$+"    Jump Start     ; "
  734.     A$=A$+"Left:           ; "
  735.     A$=A$+"    Move -10,0,2     ; "
  736.     A$=A$+"    Jump Start      ; "
  737.     A$=A$+"Up:             ; "
  738.     A$=A$+"    Move 0,-10,2     ; "
  739.     A$=A$+"    Jump Start      ; "
  740.     A$=A$+"Down:            ; "
  741.     A$=A$+"    Move 0,10,2      ; "
  742.     A$=A$+"    Jump Start      ; "
  743.     ?
  744.     B$=B$+"Start: Pause        ; "
  745.     B$=B$+"    If X>RA Jump Right ; "
  746.     B$=B$+"    If X<RA Jump Left  ; "
  747.     B$=B$+"    If Y>RB Jump Up   ; "
  748.     B$=B$+"    If X<RB Jump Down  ; "
  749.     B$=B$+"    Jump Start     ; "
  750.     B$=B$+"Right:           ; "
  751.     B$=B$+"    Move 10,0,2     ; "
  752.     B$=B$+"    Jump Start     ; "
  753.     B$=B$+"Left:           ; "
  754.     B$=B$+"    Move -10,0,2    ; "
  755.     B$=B$+"    Jump Start     ; "
  756.     B$=B$+"Up:            ; "
  757.     B$=B$+"    Move 0,-10,2    ; "
  758.     B$=B$+"    Jump Start     ; "
  759.     B$=B$+"Down:           ; "
  760.     B$=B$+"    Move 0,10,2     ; "
  761.     B$=B$+"    Jump Start     ; "
  762.     ?
  763.     Channel 1 To Bob 1
  764.     Amal 1,A$
  765.     Channel 2 To Bob 2
  766.     Amal 2,B$
  767.     Amal On 1
  768.     Wait Vbl
  769.     Amal On 2
  770.     ?
  771.     Repeat
  772.       Inc SCORE
  773.     Until Bob Col(1)
  774.     Boom
  775.     Print "YOU ARE DEAD!!!! YOUR SCORE IS";SCORE
  776.     Update
  777.  
  778. That brings us to the end of a very practical column!
  779.  
  780.  
  781. Issue 49 ­ June 1992
  782. ? Creating wonderful worlds and "alternate realities" with your Amiga's 4,096 colours
  783.  
  784. Your Amiga is blessed with a wonderful collection of 4,096 different colours. With these colours we can create new worlds and alternate realities with art packages like Deluxe Paint. With Amos we can go a step further and use the power of colour to produce animation.
  785.  
  786. Before we go into too much detail, it will help for you to know a little bit about the way colours are handled by the Amiga. Under ordinary circumstances you can display 32 individual colours on-screen. These are stored in colour registers. You can think of a colour register as being an empty paint pot, which we can fill up with any colour.
  787.  
  788. At its simplest form you can see colour cycling at fairgrounds and fancy Christmas displays. This happens when  a string of unlit bulbs are switched on in sequence one at a time. This gives the illusion that a bulb is moving along. We can demonstrate this with a simple program.
  789.  
  790. The first step is to open up our screen, so go into the Amos editor and type:
  791.     
  792.     Screen Open 0,320,200,16,Lowres
  793.     Flash Off
  794.     Cl 0
  795.     Curs Off
  796.  
  797. Now we must set up our palette. Remember that each of the numbers in the following line represent the "paint" that we are pouring into the paint pot (colour register).
  798.  
  799. The colour which we have poured into colour register number one ­ remember that the 32 different colour registers are labelled from 0 to 31 ­ is white ($FFF) and represents our bulb which is switched on:
  800.     
  801.     Palette
  802.      $0,$FFF,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,
  803.     
  804. Now we must draw our lightbulbs. Each one will use a different colour, selected with the PEN command:
  805.     
  806.      Paper 0
  807.     For LOP=1 To 15
  808.      Pen LOP
  809.      Wait Vbl
  810.      Print "0";
  811.     Next LOP
  812.     
  813. The final stage is to start the colour cycling up. We will do this using the Shift command, which uses four parameters. The first is the speed at which the colours will cycle, the second and third specify the start and end colour registers which will be cycled and the final parameter is for special effects - which we will not be using!
  814.  
  815. Just how does it work? Well, the Shift command will move the colour stored in register number 1 into register number 2, the colour in register 2 into register 3, 3 into 4, 4 into 5 etc. It's a bit like pouring the paint from one pot into another!
  816.     
  817.     Shift Up 2,1,15,1
  818.     Direct
  819.  
  820. That's it. Simple, huh?
  821.  
  822. Another interesting use of colour cycling is to produce weird backgrounds for games and demos ­ or hypnotising friends and relatives!
  823.  
  824. In the next example we will draw a small block 16 x 16 pixels in size, grab it as a Bob and finally paste it all over the screen. Once again, our screen must be opened up, and a palette selected. In this case I have used shades of blue:
  825.     
  826.     Screen Open 0,320,200,16,Lowres
  827.     Flash Off
  828.     Cls 0
  829.     Palette $0,$5,$6,$8,$9,$B,$C,$E,$F
  830.  
  831. Now we will read in the data ­ sorry, but there is quite a lot of it! ­ and draw it onto the screen:
  832.     
  833.      For Y=0 To 15
  834.      For X=0 To 15
  835.       Read SPOT
  836.        Ink SPOT
  837.       Plot X,Y
  838.      Next X
  839.     Next Y
  840.     
  841. By using the Get Bob command we can grab this small block and stick it all over the screen, 20 blocks across and 12 blocks down:
  842.     
  843.      Get Bob 1,0,0 To 16,16
  844.     For Y=0 To 11
  845.      For X=0 To 19
  846.       Paste Bob X*16,Y*16,1
  847.      Next X
  848.     Next Y
  849.     
  850. We must now start that funky colour cycling! This time we will be cycling colours 1 to eight:
  851.     
  852.  Shift Up 4,1,8,1
  853.  End
  854.  Data $1,$1,$1,$1,$1,$1,$1,$1,$1,$2,$3,$4,$5,$6,$7,$8
  855.  Data $1,$2,$2,$2,$2,$2,$2,$2,$1,$2,$3,$4,$5,$6,$7,$7
  856.  Data $1,$2,$3,$3,$3,$3,$3,$1,$2,$3,$4,$5,$6,$6,$6,$6
  857.  Data $1,$2,$3,$4,$4,$4,$4,$4,$1,$2,$3,$4,$5,$5,$5,$5
  858.  Data $1,$2,$3,$4,$5,$5,$5,$5,$1,$2,$3,$4,$4,$4,$4,$4
  859.  Data $1,$2,$3,$4,$5,$6,$6,$6,$1,$2,$3,$3,$3,$3,$3,$3
  860.  Data $1,$2,$3,$4,$5,$6,$7,$7,$1,$2,$2,$2,$2,$2,$2,$2
  861.  Data $1,$2,$3,$4,$5,$6,$7,$8,$1,$1,$1,$1,$1,$1,$1,$1
  862.  Data $1,$1,$1,$1,$1,$1,$1,$1,$8,$7,$6,$5,$4,$3,$2,$1
  863.  Data $2,$2,$2,$2,$2,$2,$2,$1,$7,$7,$6,$5,$4,$3,$2,$1
  864.  Data $3,$3,$3,$3,$3,$3,$2,$1,$6,$6,$6,$5,$4,$3,$2,$1
  865.  Data $4,$4,$4,$4,$4,$3,$2,$1,$5,$5,$5,$5,$4,$3,$2,$1
  866.  Data $5,$5,$5,$5,$4,$3,$2,$1,$4,$4,$4,$4,$4,$3,$2,$1
  867.  Data $6,$6,$6,$5,$4,$3,$2,$1,$3,$3,$3,$3,$3,$3,$2,$1
  868.  Data $7,$7,$6,$5,$4,$3,$2,$1,$2,$2,$2,$2,$2,$2,$2,$1
  869.  Data $8,$7,$6,$5,$4,$3,$2,$1,$1,$1,$1,$1,$1,$1,$1,$1
  870.      
  871. Have fun with colour cycling and send in any examples that you come up with.
  872.  
  873. We have seen how to create a simple Pacman-type game in Amos, but what's next? How about education! An absolute wealth of educational software has appeared in shops and in public domain catalogues since the release of Amos. 
  874.  
  875. Many people who have good ideas but have been unable to implement them into traditional languages ­ like Amiga Basic ­ have found that Amos allows them to breathe life into their ideas.
  876.  
  877.  
  878. Issue 50 ­ July 1992
  879. ? Producing smooth and fast scrolls for use in games
  880.  
  881. Many people bought Amos in the belief that it would let them make fantastic software with ease, save the universe as we know it and make the perfect cup of coffee.
  882.  
  883. Unfortunately life is never that simple and to get any satisfaction from using this language you will have to get to know your Amiga and its capabilities a little better. It also helps to have good Colombian beans.
  884.  
  885. There are two main methods of producing scrolling screens. The first is to take a series of interconnecting picture blocks, put one on the screen, move it a bit and then place the next section.
  886.  
  887. This is known as a software scroll because it is up to us ­ the programmers ­ to do all of the hard work. Xenon II uses this type of scrolling. One of the advantages of software scrolling is that it requires very little memory, because you really only have to have a standard sized screen open which is 320 x 200 pixels in size.
  888.  
  889. A hardware scroll is something which is handled mainly by the Amiga's custom chips, which are known as hardware. It is produced by defining a big picture, looking at one section of the picture and then panning across the rest, just like a television looking at a wall-mounted mural. Kick Off uses this type of scrolling.
  890.  
  891. Although fast, hardware scrolling eats up lots of memory. Fortunately, the ease with which we can manipulate a hardware scroll more than makes up for the memory consumption. Before we do this I think we should look at how versatile the Amiga's screen system really is.
  892.  
  893. Amiga screens are something special. You need to imagine them not as literal pictures but as a window looking into your machine's memory. By moving our viewpoint around we can examine almost any part of the chip memory contained inside the Amiga. Incidentally, this is how many graphics "grabbers" work.
  894.  
  895. Amos allows us to manipulate these "windows on the world" using Screen Display and Screen Offset commands. Screen Offset controls our view of the computer's memory through our window, while Screen Display controls the size of this window and its position on the monitor.
  896.  
  897. OK, now we all know how to open a screen inside Amos, don't we? It's pretty simple ­ load Amos and make sure you are inside the editor (not Direct Mode). Type this line in:
  898.  
  899.     Screen Open 0,320,200,16,Lowres
  900.  
  901. This tells Amos to create screen number 0 with a horizontal resolution of 320 pixels, a vertical resolution of 200 pixels and 16 colours in lo-res mode, which means the pixels are pretty square and chunky. We now have a screen we can experiment with.
  902.  
  903. The next step is to define two variables XSIZE and YSIZE ­ these will tell Amos how big our window will be:
  904.  
  905.     XSIZE=320
  906.     YSIZE=200
  907.  
  908. OK, now we must start a loop which will allow us to change the characteristics of this window with the mouse buttons. Every time we go around the loop, the mouse co-ordinates are put into the variables X and Y.
  909.  
  910. These are then used to position the window on your monitor. It sounds confusing, but if you imagine the window as a piece of paper being moved around the desk ­ which is your monitor! ­ it may sound a little clearer:
  911.  
  912.     Repeat
  913.     X=X Mouse-100
  914.     Y=Y Mouse-160
  915.  
  916. Now we must check the state of the mouse keys. If the left button is pressed the variable XSIZE is decremented. If the right button is pressed the variable YSIZE is decremented. The command ADD allows a little more control over variables than the standard INC or DEC commands. By using ADD we can make the number contained in XSIZE wrap from 0 to 320 with very little work:
  917.  
  918.     If Mouse Key=1
  919.         Add XSIZE,-1,1 To 320
  920.     End If
  921.     If Mouse Key=2
  922.         Add YSIZE,-1,1 To 200
  923.     End If
  924.  
  925. OK, now for the magic command. As you can see the first parameter is the screen number., followed by the X and Y positions plus XSIZE and YSIZE:
  926.  
  927.     Screen Display 0,X,Y,XSIZE,YSIZE
  928.  
  929. The final part of our program waits for you to press both mouse keys before it stops:
  930.  
  931.     Until Mouse Key=3
  932.     End
  933.  
  934. I hope this has not been too complicated to follow so far. The concepts are simple, but I must admit that the whole subject can become overpowering!
  935.  
  936. I have now introduced you to the basics of using Screen Display, but what about Screen Offset? It is this command which actually creates the scrolling. If we designed a standard screen size and used Screen Offset to look above ­ or below ­ it, we would see what is contained in those portions of memory.
  937.  
  938. To start off with, let's open up our screen by typing the following lines into the Amos editor (remember to Save your last program if you want to keep it):
  939.  
  940.     Screen Open 0,320,200,4,Lowres
  941.     Flash Off
  942.     Hide On
  943.     Curs Off
  944.     Palette $0,$90
  945.     Cls 1
  946.  
  947. You will notice that I have reduced the amount of colours from the standard 16 down to four. I have also increased the size of the screen to 600 pixels high, which is three times the height of a normal screen.
  948.  
  949. The next Screen Display command features four commas in succession. This is not a typing error! It tells Amos to use its own defaults instead of the missing parameters. The last part of the line tells Amos that we only want to display 200 lines of the 600 line screen:
  950.  
  951.     Screen Display 0,,,,200
  952.  
  953. I am not a great lover of football ­ or football simulation computer games ­ but they can be useful to demonstrate the principles we are dealing with here. So in the best tradition of Blue Peter, here is a pitch I drew earlier:
  954.  
  955.     Draw 0,299 To 320,299
  956.     Box 0,0 To 319,599
  957.     Circle 160,299,105
  958.  
  959. Even though we cannot see the whole screen, Amos will draw it for us. Neat, huh? The penultimate step in this program is to let Amos know which part of the 600-line screen we wish to display inside our small 200-line window. Once again, the Screen Offset command contains a couple of commas, which tells Amos to use the default value for the X position of our view:
  960.  
  961.     YPOS=0
  962.     Screen Offset 0,,YPOS
  963.  
  964. Now for the exciting bit! By pressing the left mouse button the screen will scroll smoothly upwards by telling Amos ­ through the Screen Offset command ­ to look at a different part of the picture held in memory through our small screen or "window". If we press the right button the screen will scroll downward:
  965.  
  966.     Repeat
  967.         If Mouse Key=1 and YPOS.0
  968.             Add YPOS,-5
  969.             Screen Offset 0,,YPOS
  970.         End If
  971.         If Mouse Key=2 and YPOS,400
  972.             Add YPOS,5
  973.             Screen Offset 0,,YPOS
  974.         End If
  975.  
  976. We must put a WAIT VBL command here to tell Amos to slow down. Try removing it to see how fast the program runs!
  977.  
  978.     Wait Vbl
  979.     Until Mousekey=3
  980.  
  981. Why not experiment and see what you come up with?
  982.  
  983.  
  984. Issue 51 ­ August 1992
  985. ? Generating Amiga windows and menus
  986.  
  987. If you are coding something other than a game, you?ll have to get used to generating Amiga windows and menus. This is much easier in Amos than it is in, say, AmigaBasic, where you have to specify everything so precisely you might as well draw it on the screen with a Biro.
  988.  
  989. Getting a screen together is easy enough with the Screen Open command, but what do you have to do to make the screen and its windows act like a normal Amiga program? I?ve been doing a lot of this sort of thing lately, so try this listing for size:
  990.  
  991.     Screen Open 0,640,256,16,Hires
  992.  
  993. Nice and simple to start with. Just a med-res screen to give you that utility look. Now we define our menus:
  994.  
  995.     MenuS(1)=? Project     ?
  996.     MenuS(1,1)=? Load     ?
  997.     MenuS(1,2)=? Load As...     ?
  998.     MenuS(1,3)=? Save     ?
  999.     MenuS(1,4)=? Save As...     ?
  1000.  
  1001. That?s menu 1 sorted and as you can see it?s a very simple procedure to name the menus, with 1 being the menu title, and 1,1 being a submenu. We do the same for the next menu, but with a little twist:
  1002.  
  1003.     MenuS(2)=? CyberSpace     ?
  1004.     MenuS(2,1)=? Engage!     ?
  1005.     MenuS(2,1,1)=? Are you sure?     ?
  1006.     MenuS(2,1,1,1)=? Yes - GO!!     ?
  1007.     MenuS(2,1,1,2)=? No - Abort     ?
  1008.     MenuS(2,2)=? Morph     ?
  1009.     MenuS(2,3)=? ID scan     ?
  1010.     MenuS(2,4)=? Alter ID     ?
  1011.  
  1012. You can go on adding submenus like 2,1,1,1,1,1 to infinity, but bear in mind that anything other than one or two submenus really gets on the operators? nerves after a very short while. Finally we turn the menus on:
  1013.  
  1014.     Menu On
  1015.  
  1016. and at this point the menus are active. You can of course turn them off later if you don?t want anyone using the menus at a certain point in the program. Finally, for the benefit of our listing, a few cosmetic and diagnostic details:
  1017.  
  1018.     Curs Off : Cls O
  1019.     Do
  1020.     Print ?Menu= ?;Choice(1);?
  1021.     Selection= ?;Choice(2)
  1022.     Loop
  1023.  
  1024. You can now run the program. Notice how the menu and selection numbers change when you select a different menu item. This is how you know what the user has selected, and it?s simply that.
  1025.  
  1026. Find out what choice 1 and 2 are and you know what menu item was under the pointer when the user let go of the RMB. But to really get to grips with the menus, especially if you have a number of them, you have to use the Amos auto menuing system with On Menu On. This takes a little bit of practice, but it?s really quite simple. The revised program starts the same, pretty much:
  1027.  
  1028.     Screen Open 0,640,256,16,Hires
  1029.     Cls 0 : Curs Off
  1030.     MenuS(1)=?Project     ?
  1031.     MenuS(1,1)=?Load     ?
  1032.     MenuS(1,2)=?Load As...     ?
  1033.     MenuS(1,3)=?Save     ?
  1034.     MenuS(1,4)=?Save As...     ?
  1035.     MenuS(2)=?CyberSpace     ?
  1036.     MenuS(2,1)=?Engage!     ?
  1037.     MenuS(2,1,1)=?Are you sure?     ?
  1038.     MenuS(2,1,1,1)=?Yes - GO!!     ?
  1039.     MenuS(2,1,1,2)=?No - Abort     ?
  1040.     MenuS(2,2)=?Morph     ?
  1041.     MenuS(2,3)=?ID scan     ?
  1042.     MenuS(2,4)=?Alter ID     ?
  1043.  
  1044. But at this point it diverts into new territory:
  1045.  
  1046.     On Menu Proc PROJECT,CYBER
  1047.     On Menu On
  1048.     Menu On
  1049.     Wait Key
  1050.  
  1051. This turns on the auto menuing system and waits for you to either make a selection from the menus or press a key on the keyboard. The PROCs you mentioned in the ON MENU ON statement are then defined somewhere else in the program, like right now for example:
  1052.  
  1053.     LISTINGS MACRO2 Procedure PROJECT
  1054.     Cls
  1055.     Y=Choice(2)
  1056.     Locate 0,22 : Print ?Menu: Project?
  1057.     Locate 0,23
  1058.     If Y=1 Then Print ?Load what??
  1059.     If Y=2 Then Print ?Load as what??
  1060.     If Y=3 Then Print ?Save what??
  1061.     If Y=4 Then Print ?Save as what??
  1062.     OM
  1063.     End Proc
  1064.     Procedure CYBER
  1065.     Cls
  1066.     Y=Choice(2)
  1067.     Locate 0,22 : Print ?Menu: Cyberspace?
  1068.     Locate 0,23
  1069.     If Y=1 Then Print ?Yes Or No? Which is it??
  1070.     If Y=2 Then Print ?Morph yourself?
  1071.     If Y=3 Then Print ?Okay you?re scanned?
  1072.     If Y=4 Then Print ?You can?t change ID?
  1073.     OM
  1074.     End Proc
  1075.     End
  1076.     Procedure OM
  1077.     On Menu On
  1078.     End Proc
  1079.  
  1080. And there you have it. The responses are put into PROCs and this makes the whole thing a lot simpler. You only have to scan for one variable CHOICE(2) as the first one, the menu itself is chosen for you automatically, and you?re sent right to the PROC that deals with that menu.
  1081.  
  1082. Once you?ve got subroutines accepting input from menus, you?ve got yourself the basis for a mighty fine menu driven utility program.
  1083.  
  1084.  
  1085. Issue 52 ­ September 1992
  1086. ? Altering text font, colour and sizes
  1087.  
  1088. Text in computer programs is something you take for granted. I know I do, and it?s hard to think beyond the kind of things that have been possible in AmigaBasic, which is what most people?s programming experience consists of pre-Amos.
  1089.  
  1090. But Amos opens up new vistas of programming, and simply too. This month we?ll be looking at how you can spice up your text, whether it be a game logo, high score table, or just the title screen of your new business program.
  1091.  
  1092. Text in a computer program tells you two things. The words on the screen tell you what to do, and the style with which they do it tells you a lot about the programmer?s attention to detail.
  1093.  
  1094. Normal text tricks include clever formatting and changes of colour. But more impressive are changes of font and size. It?s like the difference between typing on a typewriter and making up your text in a DTP program.
  1095.  
  1096. Firstly if you don?t want to faff about with fonts, make your titles a different colour with Pen and centre them with Centre. But there are two kinds of text in Amos - normal text and what they call ?graphic text?. Normal text is printed to the screen with a Print statement, but graphic text needs to be put to the screen using Text, like so:
  1097.  
  1098.     Rem * Simple Font Prog 1 *
  1099.     Get Fonts
  1100.     Paper 8
  1101.     Set Font 8
  1102.     Ink 2 : Text 5,50, ?Amiga Computing?
  1103.  
  1104. The Get Fonts command scans the ROM and Fonts: directory on disk for fonts, and Set Font sets  the font to be printed to the appropriate font in the pecking order.
  1105.  
  1106. The colour of graphic fonts is set using the Ink command rather than Pen (they?re drawn rather than printed, being graphics!). Once you have graphic text under control you can do all manner of technical tricks like putting shadows under the text
  1107.  
  1108.     Rem Totally Fontastic!
  1109.     Rem
  1110.     Paper 8 : Curs Off : Hide : Cls
  1111.     Get Fonts
  1112.     For F=1 To 30
  1113.     If Font$(F)
  1114.     Clw
  1115.     Print Font$(F)
  1116.     Set Font F
  1117.     For Y=20 To 150 Step 20
  1118.     SHAD[10,Y, ?Amiga Computing?,1]
  1119.     Next
  1120.     Wait Key
  1121.     End If
  1122.     Next
  1123.     Procedure SHAD[X,Y,A$,D]
  1124.     Gr Writing 0
  1125.     Ink 0
  1126.     For DX=-D To D
  1127.     Text X+DX, Y-D,A$ : Text X+DX, Y+D,A$
  1128.     Next
  1129.     For DY=-D+1 To D-1
  1130.     Text X-D, Y+DY,A$ : Text X+D,Y+DY,A$
  1131.     Next
  1132.     Ink 2 : Text X,Y,A$
  1133.     End Proc
  1134.  
  1135. using JAM1 mode via the GR WRITING command to ensure a good impression. Or if you?re particularly clever you can even add a drop shadow using the same program but simply changing the last two lines:
  1136.  
  1137.     Ink 2 : Text X-2,Y-2,A$
  1138.     End Proc
  1139.  
  1140. This offsets the final white printing of the characters up and to the left of the black outline, creating a drop shadow. Experiment with the code and see how many effects you can do. How about making the last print in the same Ink as the Paper colour, for an outline font?
  1141.  
  1142. More exotic effects can be obtained using Aaron Fothergill?s CText program, in which graphic text is taken to its extreme. If you get this program (either from Aaron?s Amos Club or Déjà Vu Software) you can create a font in Deluxe Paint and include it in your program just like the pros do.
  1143.  
  1144. The font is stored on an IFF picture file like the example screen on this page, and then scanned into CText a letter at a time. Then you can print it to the screen in the same way you would ordinary text, or even do a scrolly message across another screen.
  1145.  
  1146. Finally, Rainbow text is easy, and very effective. Basically what you have is a rainbow you set up using the copper, and the text is like a lot of holes punched through a screen covering the rainbow, giving you rainbow coloured text! Try this listing to give you a taster:
  1147.  
  1148.     Rem * RainbowText.Amos *
  1149.     Rem
  1150.     Cls 0 : Curs Off : Hide
  1151.     Gosub STRIPES
  1152.     For X=0 To 23
  1153.     Pen 1 : Paper 0 : Print ?Rainbow Text!!!
  1154.     Rainbow Text!!!?
  1155.     Next X
  1156.     Wait Key
  1157.     ?
  1158.     STRIPES:
  1159.     Set Rainbow 0,1,280,??,??,??
  1160.     Rainbow 0,0,0,280
  1161.     Colour Back 0
  1162.     Restore RDATA
  1163.     For C=0 To 279 : Read CVA : Rain(0,C)=CVA
  1164.     Next C : View
  1165.     Return
  1166.     RDATA:
  1167.     Data $0,$0,$0,$111,$222,$333,$444,$555
  1168.     Data $666,$777,$888,$999,$AAA,$BBB,$CCC,$DDD
  1169.     Data $EEE,$FFF,$FFF,$EEE,$DDD,$CCC,$BBB,$AAA
  1170.     Data $999,$888,$777,$666,$555,$444,$333,$222
  1171.     Data $300,$200,$300,$400,$500,$600,$700,$800
  1172.     Data $900, $A00,$B00,$C00,$D00,$E00,$F00,$F00
  1173.     Data $E00,$D00,$C00,$B00,$A00,$900,$800,$700
  1174.     Data $600,$500,$400,$300,$200,$20,$30,$40
  1175.     Data $50,$60,$70,$80,$90,$A0,$B0,$C0
  1176.     Data $D0,$E0,$F0,$F0,$E0,$D0,$C0,$B0
  1177.     Data $A0,$90,$80,$70,$60,$50,$40,$30
  1178.     Data $30,$0,$1,$2,$3,$4,$5,$6
  1179.     Data $7,$8,$9,$A,$B,$C,$D,$E
  1180.     Data $F,$F,$E,$D,$C,$B,$A,$9
  1181.     Data $8,$7,$6,$5,$4,$3,$2,$1
  1182.     Data $0,$0,$22,$33,$44,$55,$66,$77
  1183.     Data $88,$99,$AA,$BB,$CC,$DD,$EE,$FF
  1184.     Data $FF,$EE,$DD,$CC,$BB,$AA,$99,$88
  1185.     Data $77,$66,$55,$44,$33,$22,£110,$220
  1186.     Data $330,$440,$550,$660,$770,$880,$990,$AA0
  1187.     Data $BB0,$CC0,$DD0,$EE0,$FF0,$FF0,$EE0,$DD0
  1188.     Data $CC0,$BB0,$AA0,$990,$880,$770,$660,$550
  1189.     Data $440,$330,$220,$101,$202,$303,$404,$505
  1190.     Data $606,$707,$808,$909,$A0A,$B0B,$C0C,$D0D
  1191.     Data $E0E,$F0F,$F0F,$E0E,$D0D,$C0C,$B0B,$A0A
  1192.     Data $909,$808,$707,$606,$505,$404,$303,$202
  1193.     Data $111,$222,$333,$444,$555,$666,$777,$888
  1194.     Data $999,$AAA,$BBB,$CCC,$DDD,$EEE,$FFF,$FFF
  1195.     Data $EEE,$DDD,$CCC,$BBB,$AAA,$999,$888,$777
  1196.     Data $666,$555,$444,$333,$222,$300,$200,$300
  1197.     Data $400,$500,$600,$700,$800,$900,$A00,$B00
  1198.     Data $C00,$D00,$E00,$F00,$F00,$E00,$D00,$C00
  1199.     Data $B00,$A00,$900,$800,$700,$600,$500,$400
  1200.     Data $300,$200,$20,$30,$40,$50,$60,$70
  1201.     Data $80,$90,$A0,$B0,$C0,$D0,$E0,$F0
  1202.     Data $F0,$0,$0,$0,$0,$0,$0,$0
  1203.  
  1204. Phew! Sorry about all that data, but it?s needed to give you the rainbow stripes. And there you see it, rainbow text. Now let them try and ignore that screen!
  1205.  
  1206.  
  1207. Issue 53 ­ October 1992
  1208. ? Using Amos to improve your computer's sound
  1209.  
  1210. One of the key things which distinguishes Amos from other types of Basic is its grip on the Amiga?s breathtaking sound playing capability. But then again the whole idea of Amos is the be able to access all the functions of the Amiga rapidly and easily, using one command where previously only a few hundred would do.
  1211.  
  1212. The Amiga can grab and play sampled sounds very easily. The sound chip can be used, and samples can be put into a bank for you to use in your own programs. Amos can also play music, like the ABK files on your demo disks. But for now let?s talk about samples. Using sampled sounds is easy, and similar to the use of IFF picture files, in as much as you can load them in off disk as they are or use them from a bank.
  1213.  
  1214. You need an Amos program called Sam Maker, and this allows you to load samples and put them together into a bank in memory. The problem with loading samples from disk is that you have to BLOAD them and specify locations in memory and all that, which is a little bit technical and not to say a touch heavy on memory and resources.
  1215.  
  1216. It?s a far more elegant solution to store them in a bank as they are ready to access at any time during your program, and they are loaded instantly. Once you have your samples in a bank you can play them back at any speed, which changes the time the sample takes to play and thus the pitch of the sample.
  1217.  
  1218. So you can either have samples of speech, snatches of music, or even single notes of an instrument which you can play in a sound/noise/Pro Tracker-type program at different pitches. Playing samples in Amos is a matter of using the Sam Play command:
  1219.  
  1220.     Sam Play VOICE,SAMPLE,FREQUENCY
  1221.  
  1222. The voices your sample will use are set by setting a bit in V, like so:
  1223.  
  1224.     %1000 voice 3
  1225.     %1010 voice 3 and 2
  1226.     %1111 voices 3, 2, 1 and 0
  1227.  
  1228. This is all very well documented, but here?s an idea for you. The Amiga has four voices, and these are paired to play in either left or right stereo channel. Voices 0 and 3 play through the left speaker and 1 and 2 play through the right.
  1229.  
  1230. It struck me the other day that it would be easy to take advantage of this stereo capability and make stereo sounds - true stereo sounds, not just one sound in one ear and another in the other ear like most programs you hear/see.
  1231.  
  1232. If you want to pan a sound around in the stereo spectrum you have to alter the volume across the two stereo channels of the same sound. This is called mixing or panning in the trade.
  1233.  
  1234. To clarify that, a sound appears in a certain position in the stereo ?picture?, an imaginary 3D space with a left, right, in and out, depending on how quiet or loud it is in each ear. A noise which is soft in the left ear and loud in the right will appear to come from right of centre in front of the listener.
  1235.  
  1236. So in order to simulate stereo panning in an Amiga sound, all you have to do is put the same sound in both speakers and alter the volume of one or the other to move the sound in space! Let?s try this out. Have your Amos Data disk in one of your drives and run the following program:
  1237.  
  1238.     Screen Open 0,640,256,16,Hires
  1239.     Hide : Curs Off : Paper 0 : Cls 0
  1240.     Load ?Amos_Data:samples/samples.abk?
  1241.  
  1242. After all the usual setup, we load in some samples from the Amos Data disk. If you don?t have this in the drive it?ll prompt you, because I?ve specified the exact disk name in the Load statement:
  1243.  
  1244.     Sam Loop On
  1245.     Volume %10,0 : Volume %1,50
  1246.  
  1247. Then we turn Sam Loop On to make the sound continuous, and so make it easier to hear the stereo panning. Next we set up the initial volumes of the two voices we?ll be using, in this case voices 1 and 2, indicated by the binary codes %0010 and %0001. This sets the volume so that the right channel is silent and the left is set at 50:
  1248.  
  1249.     X=1
  1250.     Locate ,5 : Pen 4 : Centre ?AC brings you *Stereo Panning*?
  1251.     Locate ,7 : Centre ?The sound moves slowly from left to right?
  1252.  
  1253. Next we have the main program loop. The PANME procedure increments the right and decrements the left at half second intervals until the sound has travelled fully from left to right:
  1254.  
  1255.     Do
  1256.     Sam Play %11,3
  1257.     PANME
  1258.     Loop
  1259.     ?
  1260.     Procedure PANME
  1261.     P1=0 : P2=50
  1262.     Repeat
  1263.     Volume %10,P1 : Volume %1,P2
  1264.     Wait 25
  1265.     Inc P1 : Dec P2
  1266.     Until P1=50
  1267.     End Proc
  1268.  
  1269. As they say in all the old Bond movies, crude but effective. If you were very clever you could even have another sound panning the other way too.
  1270.  
  1271. Or even, and this is a really nice one, move the sound in stereo according to movements from the joystick, which also moves the sprite that the sound relates to! This would give you a real stereo effect for very little programming.
  1272.  
  1273. Simply put, this would involve the use of a simple test for the joystick direction as another procedure at the end of the program, and putting the proc name in the main loop. This routine gives you an idea of what I?m talking about:
  1274.  
  1275.     Screen Open 0,640,256,16,Hires
  1276.     Hide : Curs Off : Paper 0 : Cls 0
  1277.     Load ?Amos_Data:samples/samples.abk?
  1278.     Volume %10,25 : Volume %1,25
  1279.     P1=25 : P2=25
  1280.     Do
  1281.     Sam Play %11,3
  1282.     If Jleft(1) Then Inc P1 : Dec P2
  1283.     If Jright(1) Then Inc P2 : Dec P1
  1284.     If P1...
  1285.     If P2...
  1286.     Volume %10,P1 : Volume %1,P2
  1287.     Wait 25
  1288.     Locate 0,0 : Print P1,P2
  1289.     Loop
  1290.  
  1291. Once again it uses the samples from Amos_Data, but this time the sound pans in stereo depending on whether you move the stick left or right. The location of the sound is shown at the top of the screen.
  1292.  
  1293. Try that out at home this month, and try to make it faster still if you can. Also, you can add a facility to pan the sound in and out as well as from left to right, and move a sprite at the same time.
  1294.  
  1295.  
  1296. Issue 54 ­ November 1992
  1297. ? Manipulating and filling screens with all sorts of stuff
  1298.  
  1299. Although you may already know this, Amos has some very powerful commands for the manipulation of screens and their contents. You will know by now how to load and define screens, sure, even if you?ve only just bought the program.
  1300.  
  1301. What about moving screens around once you have them defined and loaded? Amos has a number of very useful (I love understatement, don?t you?) commands for manipulating screens, and these are easy to spot as they usually have the word ?screen? in them.
  1302.  
  1303. Screen Hide will take a screen you?ve loaded and send it away somewhere until it is needed. To show it again you just need to use the Screen Show command. Logical really, and as always in Amos Show and Hide are the exact opposite when applied to what you might call visual commands.
  1304.  
  1305. The best place to hide an Amos screen of course is in a SPACKed memory bank and a Packed Picture, as it takes up less memory. Screen Copy is used as a part of the process of scrolling all or part of screens, in combination with Def Scroll, Scroll and Screen Swap, as we see in this example:
  1306.  
  1307.     Load Iff ?name your path and picture here?,1
  1308.     Screen Open 0,320,256,32,Lowres
  1309.     Get Palette 1 : Curs Off : Flash Off
  1310.  
  1311. This is all the usual setup guff, and if you?ve got any sense you?ll stick this away as a file to merge to save you typing in all this before you begin. The file you choose is loaded into screen 1, which at the moment is invisible:
  1312.  
  1313.     Screen Copy 1 To 0 : Screen 0 : Double Buffer : Bob Update
  1314. Off
  1315.  
  1316. You?ve opened a screen 0 and you?re copying screen 1 to 0, then making the system show screen 0. Double buffering makes things nice and smooth by hiding any loading of images:
  1317.  
  1318.     S=2
  1319.     Def Scroll 1,80,80 To 240,240,0,-S
  1320.  
  1321. S is the increment of the scroll, and the Def Scroll routine defines the area of the scroll using the usual co-ordinates. Next you need to set up a loop and feed the increments to it:
  1322.  
  1323.     Repeat
  1324.     For Y=0 To 199 Step S
  1325.     Scroll 1
  1326.     Screen Copy`` 1,80,Y,240,Y+S To 0,80,240-S
  1327.     Screen Swap
  1328.     Screen Copy 1,80,Y,240,Y+S To 0,80,240-S
  1329.     Wait Vbl
  1330.     Next Y
  1331.     Screen Swap : Wait Vbl : Scroll 1
  1332.     Until Mouse Key
  1333.  
  1334. So the area defined by the Def Scroll statement is scrolled upwards using the Repeat Until loop. This is done over and over until any mouse button is pressed, at which time the program stops. Choose a picture which has some colours and shapes on it. If the picture is too plain you won?t really see the effect.
  1335.  
  1336. Screen swap uses an ?invisible? screen called the ?logical screen? on which it renders things like scrolls, like in our example. When the object or screen has been modified, the results are copied to the real screen. 
  1337.  
  1338. Logical screens are very useful for smoothing otherwise slow or clunky rendering routines. Try the last example and alter the settings to see how it changes when you adapt certain parts of the program, particularly the Def Scroll and Screen Copy lines.
  1339.  
  1340. Now then, this is when it starts to get really interesting. In the Amiga?s display system, a dual playfield is where two Amiga screens are visible at the same time, overlaid one on the other, where one is visible through the other.
  1341.  
  1342. This is a handy effect for what they call in the game reviewing business ?parallax scrolling?, like in the game Shadow of the Beast. There is a good Amos demo which parodies this effect, called Madness Week by the famous French Amos hacker Syntex. Get it from the Amos PD Library, and you?ll see what I mean.
  1343.  
  1344. ? Your letters
  1345. Paul Jermany writes: ?Why is it that when I design a sprite using the Amos Sprite Editor, for example a red apple, it appears blue on the screen, although when I use the Bob command it appears as it should? I phoned the Amos help line and they suggested the following:
  1346.  
  1347.     For 1=0 To 15
  1348.     C=Colour(1)
  1349.     Colour 16+1,C
  1350.     Next 1
  1351.  
  1352. At last I can get my sprites on the screen in their true colours, but the program failed. Is it something I?m doing wrong?? You didn?t mention Paul if you were using the Get Sprite Palette command. Are you? Of course you are. One reason for the problem is that Bobs use the screen palette and the sprites use the next 16 colours along, which is what your little proggy from Europress was all about.
  1353.  
  1354. The thing is that the Amos Sprite Editor is in fact a Bob editor, which is why if you load the objects as sprites you will get goofy colours. So use the Bob commands and have done with it, that?s my advice to you. The speed difference is minimal and the benefits of Bobs over sprites is worth it. Sprites are hardware limited, and Bobs are no limits but slightly slower. I know which I prefer.
  1355.  
  1356.  
  1357. Issue 55 ­ December 1992
  1358. ? Sprites and Bobs and how to move them around the screen
  1359.  
  1360. Almost every text written about Amos bangs on for quite some time about sprites and Bobs, and now it?s my turn.. Of course, one of the things which makes Amos so brilliant is its ability to slap objects on the screen and whizz them about as fast as you like. Normal Basic just doesn?t cut it.
  1361.  
  1362. There are Bobs and there are sprites. Sprites are limited in size, and their palette can only be the last 16 colours of a 32 colour display. So if the sprite?s palette takes some of its colours from the first 16, those colours will change with different backgrounds.
  1363.  
  1364. Great care is needed in the creation of sprites. Bobs make use of the blitter chip in the Amiga, capable of copying images to the screen at rates close to a million pixels per second. Bobs are just like sprites, but instead of being limited in amount or size, they?re unlimited. They can have any colours and resolutions, and you can use as you like on-screen.
  1365.  
  1366. Obviously the more Bobs you have on screen the more stress you put on memory and processing time, but don?t worry about that. Bear in mind, though, that Bobs are slower than sprites and use up more memory. As a rule of thumb, use Bobs for slow moving and big shapes, and use sprites for fast moving small shapes - that?s a fair division of labour. One other thing is that sprites can be made to be bigger than the limit of 16 pixels, by using what they call in Amos ?computed sprites?.
  1367.  
  1368. The computer automatically sticks sprites together to make bigger sprites. You can only have up to 128 pixels in width, as there are only eight hardware sprites. The biggest mistake people make when using sprites or Bobs is to instantly use AMAL when in fact they are going to compile the program anyway.
  1369.  
  1370. The sprite and Bob commands in Amos are so flexible you can ignore it except for the most mundane tasks, and then once you?ve compiled the program, provided your code is reasonably sensible and well ordered that is, the sprite will whizz around like nobody?s business.
  1371.  
  1372. Once you?ve mastered the basics of sprite movement, which should take you about ten minutes to suss, you face the prospect of all manner of objects whizzing about missing each other and providing no information about their position or any entertainment value whatsoever. Which is where this month?s program comes in.
  1373.  
  1374. Obviously the sprites are from the excellent Sprite 600 set, available from your Amos disks or via one of the various Amos PD outlets. In this example, the spaceship meekly waits at the end of the screen, and you can?t move it at all. The alien ship comes from the right of the screen, and when the ship is touched by the alien it explodes beautifully. First, all the usual setup stuff:
  1375.  
  1376.     Screen Open 0,320,200,16,Lowres
  1377.     Curs Off : Flash Off : Hide : Cls 0
  1378.  
  1379. OK, so far so good. All the image information for the explosions etc are in the sprite files, and like other examples which use the example sprite files, the sprites are loaded one after the other into the same sprite bank.
  1380.  
  1381.     Load ?df0:sprite_600/aliens/alien1.abk?
  1382.     Load ?df0:sprite_600/space/ship3.abk?,1
  1383.  
  1384. If you wanted to make this program a little bit easier to handle - and cut out the wait for the sprites to load from disk - you should load them in direct mode and save them off with the program.
  1385.  
  1386. To be really kind you could load the sprite files into the bank, merging them by adding the positive number to the end of the filename, and then save off the bank to disk as a new ABK file.
  1387.  
  1388.     Get Sprite Palette
  1389.     Double Buffer
  1390.  
  1391. Once we have loaded the sprites we?ve set up DOUBLE BUFFER to prevent any flickering of the sprites, and GET SPRITE PALETTE will make sure our sprites are the same colours as they should be.
  1392.  
  1393. In this case, the sprites are from the same set so they are all the same colours. If your sprites are of different palettes, you may have to re-edit them and alter the palettes to fit.
  1394.  
  1395.     Bob 1,0,80
  1396.     Bob 2,320,80
  1397.     Shared M
  1398.     M=320
  1399.  
  1400. Next we set up the initial positions of the Bobs, and then define a variable as shared for the position of the Bob in the proc called _ALIENMOVE. The reason this variable is shared is that the proc is called each time the Bob is moved, and so the variable has to be defined outside the Proc.
  1401.  
  1402. If the variable isn?t shared then it is always 0, as it never gets defined according to the Proc. In this case this means that the sprite would suddenly turn up in the same position as the ship and explode the ship right away, rather than travelling gently across the screen. It?s an early bug in this routine, which is how come I know about it! Next we loop.
  1403.  
  1404.     Do
  1405.     _SHIPANIM
  1406.     _ALIENMOVE
  1407.     If Bob Col(1) Then _YOURDEAD
  1408.     Loop
  1409.  
  1410. The main loop of the program is the DO LOOP, which will go on forever until the Ctrl-C combo is pressed. The loop runs through the main parts of the program, calling procs and then looping back to the start again.
  1411.  
  1412. Each time it calls the _ALIENMOVE proc the alien moves to the left. Each time the _SHIPANIM proc is called the ship?s tail flame animates. This is an example of animation without using AMAL. At the bottom of the proc we have the collision detect routine which will trigger the Proc called _YOUREDEAD when the alien makes contact with the ship. So add the procs:
  1413.  
  1414.     Procedure _ALIENMOVE
  1415.     M=M-5
  1416.     Bob 2,M,80,1
  1417.     End Proc
  1418.  
  1419.     Procedure _SHIPANIM
  1420.     For Y=18 To 21
  1421.     Bob 1,,,Y
  1422.     Wait Vbl
  1423.     Next Y
  1424.     End Proc
  1425.  
  1426.     Procedure _YOUREDEAD
  1427.     Boom
  1428.     For X=35 To 43
  1429.     Bob 1,0,80,X
  1430.     Wait 4
  1431.     Next X
  1432.     Pen 6 : Paper 0 : Centre ?Kerboom! Yup, you?re dead!?
  1433.     Wait Key
  1434.     End
  1435.     End Proc
  1436.  
  1437. And that?s that. The _YOUREDEAD proc makes a boom noise and then animates the explosion sequence from the sprite bank. This won?t work if the sprites are any others than the ones specified, as they have specific images in the bank which do certain jobs.
  1438.  
  1439. The sprite movement is a little jerky, even with double buffering. But you can pep this up a little bit with careful program structure. As usual, with any kind of coding planning is everything, and you have to carefully trace all your procs and loops to make sure that nothing is happening out of turn and every routine is working efficiently. Obviously all these problems vanish to a certain extent when you compile a program.
  1440.  
  1441.  
  1442. Issue 56 ­ January 1993
  1443. ? Shedding some light on the subject of windows
  1444.  
  1445. The Amiga is a WIMP system, and by this I don't mean it backs away from a fight. The idea of a computer interface containing windows, icons, mice and pointers was originally developed by Xerox at Palo Alto Research Centre.
  1446.  
  1447. When the Amiga was designed in 1984/5, GUIs were all the range, so the designers incorporated a mouse and a GUI called Workbench in the new machine. Only with Amos can we get the real power of windows and menus. Although they're not the kind of windows you're used to in Intuition, they are as functional.
  1448.  
  1449. If the type of programs you want to write err towards productivity or utilities, then you'll have to use the windowing functions of Amos. A window is basically an independent little area of text and graphics on the screen. To open a window on the screen you must employ the WIND OPEN command , like so:
  1450.  
  1451.     Wind Open 1,10,10,50,10
  1452.  
  1453. This, for example would open a window on to the screen (window 1) which would have its top left corner at screen location 10,10 and would be 50 characters wide by 10 characters deep. The point of this is that you can have two or more windows on the screen at the same time, all with their own text and graphics, like this:
  1454.  
  1455.     Screen Open 0,640,200,16,Hires
  1456.     Cls 0
  1457.     Flash Off
  1458.     Paper 7: Wind Open 1,0,0,40,20 : Print "This is window number 1..."
  1459.     Paper 4 : Wind Open 2,320,0,40,20 : Print "...and this is number 2!"
  1460.     Wait Key
  1461.  
  1462. Each window acts like a little version of the screen and anything you can write to a screen you can send to a window. Although the windows you get in Amos aren't the same as the kind of thing you are used to in AmigaDOS, they still have a range of styles and shapes, and can be made to act like "real" windows with the minimum of tweaking.
  1463.  
  1464. For example, you can re-size them and even add gadgets like Intuition, but all this must be done manually as Intuition is not loaded when Amos is running, alas (all this is changing with Amos Professional, of course).
  1465.  
  1466. Re-sizing is a good example so let's look at that. Let's make a window on the screen which you can pull at the bottom right-hand corner by clicking on it with the left mouse button. The window can be resized on the screen, and when you let go of the button the window snaps to that shape.
  1467.  
  1468. In order to grab anything on the screen ­ unlike the very convenient Intuition code which does it all for you ­ you have to draw a window and then describe a AZone around it to sense the presence of a mouse-click.
  1469.  
  1470. Then once you've sensed it you have to see where it moves, and then resize the window with WIND SIZE. In this example, we first open a hi-res screen and set the colours as normal:
  1471.  
  1472.     Screen Open 0,640,256,16,Hires
  1473.     Paper 0 : Cls 0
  1474.  
  1475. The we activate WIND SAVE, which mean our windows are smart and don't screw up anything on the screen below them. This is really groovy because it means you can open a window over a game screen for example,. like an IFF file. and nothing on the screen will be erased when you close the window:
  1476.  
  1477.     Wind Save
  1478.  
  1479. Next we RESERVE ZONE, which is what you do every time you are about to SET ZONE. What this means is that if you Reserve Zone 1 you are basically saying "look, I'm going to define a zone later on in the program, so allocate some memory for it and I'll get back to you":
  1480.  
  1481.     Reserve Zone 1
  1482.  
  1483. Now we set up all the characteristics of the window we'll be defining, in this case Window 1 is a 20 x 20 character window, whose top left corner is positioned at location 10,50 on the screen. After that we set the BORDER and TITLE TOP functions to describe a little bit more about the window, like the title text, in this case "Grab my corner, man!" and the colours of the border:
  1484.  
  1485.     Wind Open 1,10,50,20,20,1
  1486.     Border ,0,4
  1487.     Title Top " Grab my corner, man! "
  1488.     Set Zone 1,10,50, To 10+160,50+160
  1489.  
  1490. The last bit is the interesting part. Next we open up the zone we promised earlier. It covers the area taken up by the window, and does this by specifying the Zone number, in this case 1, and the co-ordinates of the top left and bottom right corners of the Zone. 
  1491.  
  1492. Bottom right is set here by lazily multiplying the top left figures by 160, that is to say 8 x 20, 8 being the number of pixels in a character, and 20 being the width of the window. The we're into the main loop of the program:
  1493.  
  1494.     Do
  1495.         If Mouse Key=1 and Mouse Zone=1
  1496.             DX1=10 : DY1=50 : RESIZE ME
  1497.             Reset Zone 1 : Set Zone 1,DX1,DY1 To DX2,DY2
  1498.             ZX=(DX2-DX1)/8 : ZY=(DY2-DY1)/8
  1499.             Wind Size ZX,ZY
  1500.         End If
  1501.     Print "Amos Almanac. Better than a punch up in the throat...      ";
  1502.     Loop
  1503.  
  1504. This checks for the MOUSE KEY and MOUSE ZONE functions to see if the mouse is within the zone and if it has the left mouse button pressed down. If it does the PROC called RESIZE_ME is activated.
  1505.  
  1506. The PROC then does all the work, creating a rubber band effect to show you where the sides of the window are, altering the variables containing the window co-ordinates, and checking to see if the mouse button has been released yet with the WHILE WEND loop:
  1507.  
  1508.     Procedure RESIZE_ME
  1509.         Shared DX1,DX2,DY1,DY2
  1510.         Gr Writing 2
  1511.         Repeat
  1512.             If Mouse Key=1
  1513.             DX2=X Screen(X Mouse) : DY2=Y Screen (Y Mouse)
  1514.             0DX=DX2 : 0DY=DY2
  1515.             While Mouse Key=1
  1516.                 Box DX1,DY1 To DX2, DY2
  1517.                 DX2=X Screen (X Mouse) : DY2=Y Screen (Y Mouse)
  1518.                 Box DX1,DY1 To DX2,DY2
  1519.             Wend
  1520.             Box DX1,DY1 To 0DX,0DY
  1521.             Box DX1,DY1 To DX2,DY2 : GOTIT=True
  1522.             If DX1>DX2 : T=DX1 : DX1=DX2 : DX2=T : End If
  1523.             If DY1>DY2 : T+DY1 : DY1=DY2 : DY2=T : End If
  1524.             End If
  1525.         Until GOTIT
  1526.         Gr Writing 1
  1527.     End Proc
  1528.  
  1529. Once the button is released the window is redrawn to the new size. When the new co-ordinates have been stored the old Zone is cancelled and re-drawn to the new size, and it's all ready to start again.
  1530.  
  1531. And there you have it, perfect windows, and not a single patch of putty in sight. Now you can create multiple-windowed programs and multi-windowed games too! How about a Dungeon Master clone in the PD then?
  1532.  
  1533.  
  1534. Issue 57 ­ February 1993
  1535. ? How to put music to your creations
  1536.  
  1537. It seems that every program on the Amiga written with Amos has some lovely piece of music to go with it. Don't you wish that you could make music like that? Well you can. 
  1538.  
  1539. It's tempting to steal other people's music off of bulletin boards, demos and so on. But wait, don't touch that dial. The tracker programs you need to make beautiful music are all public domain, with the exception of certain versions of MED which are what they call "licenceware". 
  1540.  
  1541. These disks costs a bit more than PD disks, but the author of the program gets a royalty every time the program is sold. They almost always feature what we call in the trade a "pattern editor" like you find on most modern drum machines and certain Midi sequencers. 
  1542.  
  1543. The sounds in trackers are always samples, like the kind you can make with your own sound sampler, with the exception again of MED which also uses the sound chip in the Amiga to create synthesized sounds, what we call "chip music". Most trackers come with disks of sounds for you to get started. The way they work is that you assemble patterns, short sequences of music lasting for 64 beats. 
  1544.  
  1545. Then when you've made a pattern for your verse, chorus and other fill-ins etc, you chain them all together to make a complete piece of music. You specify which pattern you'd like to play and in what order, and the program plays each pattern in turn to make meaningful music. Sometimes. 
  1546.  
  1547. So for example you could have an intro on pattern 1, a verse on pattern 2, a chorus on pattern 3 and a fill-in on pattern 4. The real kick of a pattern-based sequencer is that you only have to input your patterns once and then they can be played and arranged as many times as you like, rather than a more linear system which would mean you'd have to type the tune in every time. 
  1548.  
  1549. Creating pleasant music with a tracker is easy, as you can have four tracks (in some cases even eight with programs like OctaMED Professional) and you can put the notes in one at a time in what we call "step time", or play along with the other tracks live on the keyboard in what is termed "real time". 
  1550.  
  1551. Step time is easier for learners as you can fiddle about with each track of the pattern until it sounds right, like typing words into a wordprocessor and editing them until the spelling and syntax is perfect.
  1552.  
  1553. Once a piece of tracker music has been made, or produced, you can convert it to Amos ABK format and load it into a program or into a bank in direct mode. The Amos disks contain many different converters to serve most of the different kinds of tracker such as Noisetracker, Soundtracker, StarTrekker, Protracker, Games Music Creator, Sonix and so on. 
  1554.  
  1555. All you do is run these very clever little Amos programs and they read in a tracker file and spit out a ABK file onto disk ready to be loaded. Some of these programs work fine, but the problem is that so many of the tracker programs (being in the PD for some time now) have all been revamped and re-written so that they are very different in format from the originals. 
  1556.  
  1557. Some tracker tunes will not play properly once they've been converted. Usually the reason is that the samples are too long or the system has changed. Either the tracker has a pattern length which is variable and not fixed at 64, or it stores its samples in a different way. Luckily, there are ways around this ­ see the programs documented in the box on this page for some ideas.
  1558.  
  1559. Do try to cultivate the use of tracker programs. You'll find they are not as hard to use as you might think, and the results will be all your own work, rather than just a steal from someone else.
  1560.  
  1561. A recent addition to the Déjà Vu licenceware library is Music Engine by Paul Townsend (aka Technical Fred Software). This program lets you use tracker music without having to convert it. What this program provides is an interface between Amos and the Shell. 
  1562.  
  1563. You can use this to play many different music file formats, and this is done by running an appropriate "player program" which means you can hear the music without having to convert it.
  1564.  
  1565. Once you've bought the Music Engine program from Déjà Vu, you are free to use the source code, if it's for public domain,  shareware or licenceware use, providing of course you acknowledge the source of your source. 
  1566.  
  1567. If you want to use the routines in a piece of commercial software, however, then you have to contact the programmers to arrange a suitable fee.  Music Engine is a very powerful tool, and not just for driving music programs. The trick is a very good one, and although it's handy for music, it's powerful enough to run any program from the Workbench, effectively making your Amos system multitask with other programs. 
  1568.  
  1569. For more details of Music Engine (disk number LPD79) get in touch with Déjà Vu Software, or write direct to: Technical Fred Software, 117 Hilton Lane, Walkden, Worsley, Manchester M28 5TB. Phone or Fax: 061-703 7842. 
  1570.  
  1571. Another fine program disk from the Amos PD Library is the MED Utils disk, containing a copy of MED v2.13 and some convert utilities to make the SoundTracker modules from MED more palatable to the ST-to-ABK converters. The disk number is APD155
  1572.  
  1573. Lucky users of Amos Professional will know that, of course, Amos Pro is able to use files from MED and Noisetracker (and it's various clones) directly using libraries and features built into the program.  If you are using Amos Pro you don't need to use a converter or any of the programs mentioned. You do however need a copy of MED or Noisetracker to make the music in the first place. 
  1574.  
  1575. I should also say that the most up to date version of MED isn't in the public domain, but is available as licenceware, where the author gets a fee each time the program is bought. You can get information about MED from Amiganuts United, 12 Hinkler Road, Southampton SO4 6FT
  1576.  
  1577.  
  1578. Issue 58 ­ March 1993
  1579. ? Vectors ­ what they are and how to move them
  1580.  
  1581. Moving sprites on the screen is a pain in the bum, and no mistake. First you have to get the damn things moving and then you've got to hold their hand every step along the way, seeing what they hit, and then deciding how to bounce off or explode depending on what the object you've hit is. It's like having kids, or something. 
  1582.  
  1583. Wouldn't it be so much nicer if you could just send an object off in a certain direction and not worry about it until it actually does hit something? Well, you can. But first a bit of maths (groan). No, don't turn the page. Maths is a good thing. Keep that thought in mind and you'll last a lot longer as a programmer!
  1584.  
  1585. Vectors are a method of moving objects around quickly and simply, with no complex calculations or faffing about. They should be thought of as a change of direction of an object (or point in space), rather than the usual way of moving objects which is manually hiking them about using INC, DEC or things like X=X+1. 
  1586.  
  1587. It's the difference between picking a toy car up in the air and putting it manually in another place (the old method) and pushing it along the ground and letting go (like vectors). In Amos terms it works like this. As usual you use the standard pair of variables to hold the X and Y co-ordinates of the sprite or Bob position. So for example this is the vector demo program:
  1588.  
  1589.     Curs Off : Hide : Flash Off : Cls 0 : Ink 4,4 : Paper 0
  1590.     Input "What X ";DX#
  1591.     Input "What Y ";DY#
  1592.  
  1593. It's traditional to use the variables DX and DY, as these variables will tell anyone reading your program that these are vectors. If your vectors are designed to use an FPU (floating point unit), then append them with a hash or # symbol. 
  1594.  
  1595. In this demo program you start by inputting the x and y direction vectors ­ this has a result on the direction that the sprite will go. It's best to try a range of numbers between -8 and 8 for each of the vectors. First the vectors you require are accepted through the input command and stored in two variables called DX and DY:
  1596.  
  1597.     Cls 0 : Bar 0,0 To 5,5
  1598.     Get Bob 1,0,0 To 6,6
  1599.     Cls 0
  1600.  
  1601. The Bob used in the program is grabbed from the screen using Get Bob, having first been placed there using a Bar command. This is a good way of making simple sprites without having to mess about with sprite editors or anything silly like that. Next we want to talk about X and Y, which in this case are floating point numbers so they are appended with #:
  1602.  
  1603.     X#=160 : Y#=100
  1604.  
  1605. Then the start position of the Bob is set to X=160 and Y=100, or slap dab in the middle of the screen, as the screen we are looking at 320 by 200:
  1606.  
  1607.     While X#>0 and X#<320 and Y#>0 and Y#<200
  1608.        Bob 1,X#,Y#,1
  1609.        Wait Vbl 
  1610.        X#=X#+DX#
  1611.        Y#=Y#+DY#
  1612.     Wend 
  1613.     End 
  1614.  
  1615. The While Wend loop moves the sprite in the direction given by the vectors. After a while of running this program you'll be able to predict the precise direction. 
  1616.  
  1617. The Bob is moved until it reaches the edge of the screen, either less than screen position 0 at the top or left of the screen, or screen position 320 or 200 to the right or bottom.
  1618.  
  1619. Each time the While Wend goes around, the DX and DY vectors are added to the current co-ordinates, affecting the direction of the sprite. The DY and DX vectors can be positive or negative, and the speed of the movement can be varied too. 
  1620.  
  1621. You can put random speeds and random directions into a sprite making it possible to simulate the bouncing of a ball in a ping pong or squash game, or you can even simulate gravity, if you have the right formulae.
  1622.  
  1623. This is a very cool and efficient way of shifting objects around, and with a little bit of experimentation you can create very realistic movements for your sprites with very small code. A lot of Aaron Fothergill's ten-liners (Amos games written in just ten lines of code!) use vectors to chop down the amount of code needed to do very intelligent things. If you haven't seen any of these disks, then join the Amos Club right away!
  1624.  
  1625. Why aren't you a member? If you're into Amos you might like to join the club. Write for details to Amos Club, 1 Lower Moor, Whiddon Valley, Barnstaple EX32 8NW.
  1626.  
  1627. You can even do vectors in 3D, but this is more complex (worth looking in to though!). Obviously you have facilities at your disposal in Amos 3D to translate objects in 3D, but a little bit of vector magic wouldn't hurt for some really special effects. 
  1628.  
  1629. The whole point is that vector riffs are small compared to those really big routines which you can end up with when you try to do this stuff by hand.
  1630.